package io.gitee.zhangbinhub.admin.controller.api

import cn.dev33.satoken.annotation.SaCheckPermission
import cn.dev33.satoken.stp.StpUtil
import io.gitee.zhangbinhub.acp.boot.exceptions.WebException
import io.gitee.zhangbinhub.acp.boot.log.LogAdapter
import io.gitee.zhangbinhub.acp.core.common.CommonTools
import io.gitee.zhangbinhub.admin.api.ServerApi
import io.gitee.zhangbinhub.admin.api.WorkFlowApi
import io.gitee.zhangbinhub.admin.base.BaseController
import io.gitee.zhangbinhub.admin.constant.ModuleFuncCode
import io.gitee.zhangbinhub.admin.constant.RoleCode
import io.gitee.zhangbinhub.admin.po.*
import io.gitee.zhangbinhub.admin.service.WorkFlowService
import io.gitee.zhangbinhub.admin.tools.TokenTools
import io.gitee.zhangbinhub.admin.vo.*
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.annotations.ApiParam
import org.noear.solon.annotation.*
import org.noear.solon.core.handle.MethodType
import org.noear.solon.core.util.MimeType
import org.noear.solon.validation.annotation.Valid
import org.noear.solon.validation.annotation.Validated

@Valid
@Controller
@Api("工作流引擎")
open class WorkFlowController(
    @Inject logAdapter: LogAdapter,
    private val workFlowService: WorkFlowService
) : BaseController(logAdapter) {
    @ApiOperation("启动流程", notes = "启动指定的流程，并关联唯一业务主键")
    @Mapping(
        method = [MethodType.PUT],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.start,
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun start(@Body @Validated processStartPo: ProcessStartPo): InfoVo =
        TokenTools.getUserInfoFromToken().let { user ->
            if (CommonTools.isNullStr(user.id)) {
                throw WebException("找不到用户信息")
            }
            InfoVo(message = workFlowService.startFlow(processStartPo, user.id).id.toString())
        }

    @ApiOperation("查询流程任务列表")
    @SaCheckPermission(ModuleFuncCode.flowAdmin, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.GET],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.taskList + "/{processInstanceId}",
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun taskList(@Path(name = "processInstanceId") processInstanceId: Long): List<ProcessTaskVo> =
        workFlowService.findTaskList(processInstanceId)

    @ApiOperation("查询待办任务", notes = "获取当前用户的待办任务列表")
    @SaCheckPermission(ModuleFuncCode.flowPending, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.POST],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.pending,
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun pending(@Body @Validated processTaskQueryPo: ProcessTaskQueryPo): CustomerQueryPageVo<ProcessTaskVo> =
        workFlowService.findTaskList(StpUtil.getLoginIdAsString(), processTaskQueryPo)

    @ApiOperation("转办任务", notes = "转办指定的任务")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.PATCH],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.transfer + "/{taskId}/{userId}",
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun transfer(
        @ApiParam("任务ID", required = true)
        @Path(name = "taskId") taskId: Long,
        @ApiParam("目标userId", required = true)
        @Path(name = "userId") userId: String
    ): InfoVo =
        workFlowService.transfer(StpUtil.getLoginIdAsString(), taskId, userId).let {
            InfoVo(message = "任务已转办")
        }

    @ApiOperation("转办任务", notes = "转办指定的任务")
    @SaCheckPermission(ModuleFuncCode.flowAdmin, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.PATCH],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.distribute + "/{taskId}/{userId}",
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun transferAdmin(
        @ApiParam("任务ID", required = true)
        @Path(name = "taskId") taskId: Long,
        @ApiParam("目标userId", required = true)
        @Path(name = "userId") userId: String
    ): InfoVo =
        workFlowService.transferAdmin(StpUtil.getLoginIdAsString(), taskId, userId).let {
            InfoVo(message = "任务已转办")
        }

    @ApiOperation("委托办理任务", notes = "委托办理指定的任务")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.PATCH],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.depute + "/{taskId}/{acceptUserId}",
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun depute(
        @ApiParam("任务ID", required = true)
        @Path(name = "taskId") taskId: Long,
        @ApiParam("接收userId", required = true)
        @Path(name = "acceptUserId") acceptUserId: String
    ): InfoVo = workFlowService.depute(StpUtil.getLoginIdAsString(), taskId, acceptUserId).let {
        InfoVo(message = "任务已委托办理")
    }

    @ApiOperation("任务加签")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.PATCH],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.addSignature + "/{taskId}/{acceptUserId}",
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun addSignature(
        @ApiParam("任务ID", required = true)
        @Path(name = "taskId") taskId: Long,
        @ApiParam("加签userId", required = true)
        @Path(name = "acceptUserId") acceptUserId: String
    ): InfoVo = workFlowService.addSignature(StpUtil.getLoginIdAsString(), taskId, acceptUserId).let {
        InfoVo(message = "任务已加签")
    }

    @ApiOperation("任务减签")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.PATCH],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.reductionSignature + "/{taskId}/{acceptUserId}",
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun reductionSignature(
        @ApiParam("任务ID", required = true)
        @Path(name = "taskId") taskId: Long,
        @ApiParam("减签userId", required = true)
        @Path(name = "acceptUserId") acceptUserId: String
    ): InfoVo = workFlowService.reductionSignature(StpUtil.getLoginIdAsString(), taskId, acceptUserId).let {
        InfoVo(message = "任务已减签")
    }

    @ApiOperation("流程处理", notes = "可选通过或不通过")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.POST],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.process,
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun process(@Body @Validated processHandlingPo: ProcessHandlingPo): InfoVo =
        TokenTools.getUserInfoFromToken().let { user ->
            if (CommonTools.isNullStr(user.id)) {
                throw WebException("找不到用户信息")
            }
            workFlowService.skip(processHandlingPo, user.id!!).let {
                InfoVo(message = "流程处理完成")
            }
        }

    @ApiOperation("流程强制结束")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.DELETE],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.termination,
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun termination(@Body @Validated processTerminationPo: ProcessTerminationPo): InfoVo =
        TokenTools.getUserInfoFromToken().let { user ->
            if (CommonTools.isNullStr(user.id)) {
                throw WebException("找不到用户信息")
            }
            workFlowService.findProcessInstance(processTerminationPo.processInstanceId!!).let { instance ->
                if (instance.finished) {
                    false
                } else {
                    when {
                        hasAuthentication(mutableListOf(ModuleFuncCode.flowAdmin)) -> {
                            true
                        }

                        else -> {
                            instance.startUser != null && !CommonTools.isNullStr(instance.startUser!!.id) && instance.startUser!!.id == user.id
                        }
                    }
                }
            }.let {
                if (it) {
                    workFlowService.terminationFlow(processTerminationPo, user.id).let {
                        InfoVo(message = "强制结束流程实例成功")
                    }
                } else {
                    throw WebException("流程已结束或当前登录人不是流程发起人，无法终止该流程！")
                }
            }
        }

    @ApiOperation("获取流程实例", notes = "获取指定流程实例")
    @Mapping(
        method = [MethodType.GET],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.instance + "/{processInstanceId}",
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun queryInstance(
        @ApiParam("流程实例id", required = true)
        @Path(name = "processInstanceId") processInstanceId: Long
    ): ProcessInstanceVo = workFlowService.findProcessInstance(processInstanceId)

    @ApiOperation("获取流程实例", notes = "获取流程实例")
    @Mapping(
        method = [MethodType.POST],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.instance,
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun queryInstance(@Body @Validated processQueryPo: ProcessQueryPo): CustomerQueryPageVo<ProcessInstanceVo> =
        workFlowService.findProcessInstance(processQueryPo)

    @ApiOperation("获取我处理过的流程实例", notes = "获取我处理过的流程实例")
    @Mapping(
        method = [MethodType.POST],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.myProcess,
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun queryInstanceForMyProcess(@Body @Validated myProcessQueryPo: MyProcessQueryPo): CustomerQueryPageVo<ProcessInstanceVo> =
        workFlowService.findProcessInstanceForMyProcess(StpUtil.getLoginIdAsString(), myProcessQueryPo)

    @ApiOperation("获取流程历史记录", notes = "获取指定流程实例的历史处理记录")
    @Mapping(
        method = [MethodType.GET],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.history + "/{processInstanceId}",
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun queryHisTask(
        @ApiParam("流程实例id", required = true)
        @Path(name = "processInstanceId") processInstanceId: Long
    ): List<ProcessHisTaskVo> = workFlowService.findHistoryTask(processInstanceId)

    @ApiOperation("获取流程任务信息", notes = "获取指定流程任务")
    @SaCheckPermission(ModuleFuncCode.flowProcess, orRole = [RoleCode.SUPER])
    @Mapping(
        method = [MethodType.GET],
        value = "${ServerApi.basePath}${WorkFlowApi.workFlow}" + WorkFlowApi.task + "/{taskId}",
        produces = MimeType.APPLICATION_JSON_VALUE
    )
    @Throws(WebException::class)
    fun queryTaskInfo(
        @ApiParam("流程任务ID", required = true)
        @Path(name = "taskId") taskId: Long
    ): ProcessTaskVo = workFlowService.findTaskById(StpUtil.getLoginIdAsString(), taskId)
}
